package api

import (
	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/httpmvc/api"
	"gitee.com/sansaniot/ssiot-core/serrors"
	"github.com/gin-gonic/gin"
	"ssdevice/common/cron"
	cDto "ssdevice/common/dto"
	"ssdevice/internal/device/models"
	"ssdevice/internal/rule/engine"
	"strings"

	devQuery "ssdevice/internal/device/models/query"
	"ssdevice/internal/rule/model"
	"ssdevice/internal/rule/model/command"
	"ssdevice/internal/rule/model/query"
)

type Rule struct {
	api.Api
}

// FindList 获取规则信息列表
func (s Rule) FindList(c *gin.Context) {
	// 请求参数
	req := &query.RuleGetReq{}
	//	模型
	m := &model.Rule{}
	// 上下文
	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)

	//	执行
	result, count, err1 := m.FindPage(req)
	if err1 != nil {
		s.Logger.Error(err)
		s.Fail(0, err.Error())
		return
	}
	// 返回
	s.Page(count, req.GetPageSize(), req.GetPageIndex(), result)
}

// Get 获取规则信息
func (s Rule) Get(c *gin.Context) {
	// 请求参数
	req := &query.RuleGetReq{}
	// 模型
	m := &model.Rule{}
	// 上下文
	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)

	// 执行
	if err = m.GetOne(req); err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.SelectFail)
		return
	}
	// 返回
	s.Data(m)
}

// Create 创建规则
func (s Rule) Create(c *gin.Context) {
	req := &command.RuleInsertReq{}
	ruleModel := &model.Rule{}
	err := s.MakeContext(c).Bind(req).MakeModel(&ruleModel.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)
	if req.UserId != req.AgencyId {
		s.Fail(0, "没有操作规则的权限")
		return
	}

	// model赋值
	_ = req.Generate(ruleModel, c)

	// 添加规则
	if err = ruleModel.AddRule(); err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InsertFail)
		return
	}

	s.Ok(ruleModel.Id)
}

// Modify 更新规则信息
func (s Rule) Modify(c *gin.Context) {
	req := &command.RuleUpdateReq{}
	m := &model.Rule{}

	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)
	if req.UserId != req.AgencyId {
		s.Fail(0, "没有操作规则的权限")
		return
	}

	updates := make(map[string]interface{}, 6)
	err = req.Generate(updates)
	if err != nil {
		s.Logger.Error(err)
		s.Fail(0, err.Error())
		return
	}

	m.Id = req.Id
	err = m.Modify(updates)
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.ModifyFail)
		return
	}

	s.Ok(m.Id)
}

// Remove 删除规则
func (s Rule) Remove(c *gin.Context) {
	req := &command.RuleOperationReq{}
	m := &model.Rule{}

	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)
	if req.UserId != req.AgencyId {
		s.Fail(0, "没有操作规则的权限")
		return
	}

	_ = m.GetById(req.Id)
	if m.Status == model.RuleEnable {
		s.Fail(0, "删除前请先禁用规则")
		return
	}

	err = m.Remove()
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.DeleteFail)
		return
	}

	s.Ok(m.Id)
}

// Disable 停用规则
func (s Rule) Disable(c *gin.Context) {
	req := &command.RuleOperationReq{}
	m := &model.Rule{}

	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)
	if req.UserId != req.AgencyId {
		s.Fail(0, "没有操作规则的权限")
		return
	}

	m.Id = req.Id
	err = m.Disable()
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.ModifyFail)
		return
	}

	// 规则下的定时处理器启动
	processor := &model.Processor{}
	processor.Orm = env.Db
	procList, _ := processor.FindScheduledByRuleId(m.Id)

	for _, p := range procList {
		cron.RemoveTask(p.ScheduleId)

		p.Orm = env.Db
		_ = p.SaveScheduleId(0)

		env.Log.Infof("remove processor %s with schedule id %d (%s)", p.Id, p.ScheduleId, p.Schedule)
	}

	s.Ok(m.Id)
}

// Enable 启用规则
func (s Rule) Enable(c *gin.Context) {
	req := &command.RuleOperationReq{}
	m := &model.Rule{}

	err := s.MakeContext(c).Bind(req).MakeModel(&m.Model).Errors
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.InvalidParam)
		return
	}

	req.LoadUser(c)
	if req.UserId != req.AgencyId {
		s.Fail(0, "没有操作规则的权限")
		return
	}

	m.Id = req.Id
	err = m.Enable()
	if err != nil {
		s.Logger.Error(err)
		s.Fail(serrors.ModifyFail)
		return
	}

	// 规则下的定时处理器启动
	processor := &model.Processor{}
	processor.Orm = env.Db
	procList, _ := processor.FindScheduledByRuleId(m.Id)

	for _, p := range procList {
		sns := getStatSns(p.RuleId)
		// 先停用再启用
		cron.RemoveTask(p.ScheduleId)
		scheduleId := cron.AddCronTask(p.Schedule, func() { engine.ExecScheduleTask(p, sns) }, false)

		p.Orm = env.Db
		_ = p.SaveScheduleId(int(scheduleId))
		env.Log.Infof("add processor %s with schedule id %d (%s) for %d devices", p.Id, scheduleId, p.Schedule, len(sns))
	}

	s.Ok(m.Id)
}

func getStatSns(ruleId string) []string {
	// 获得规则信息
	rule := &model.Rule{}
	rule.Orm = env.Db
	_ = rule.GetById(ruleId)
	ruleSns := make([]string, 0)
	if len(rule.DevSn) > 0 {
		ruleSns = strings.Split(rule.DevSn, ",")
	}
	if len(rule.ProductId) > 0 {
		ruleProductIds := strings.Split(rule.ProductId, ",")
		sysDev := models.SysDev{}
		sysDev.Orm = env.Db
		devList := make([]models.SysDev, 0)
		if err := sysDev.FindList(&devList, cDto.MakeCondition(devQuery.SysDevQuery{ProductModelIn: ruleProductIds})); err != nil {
			return ruleSns
		}
		if len(devList) == 0 {
			return ruleSns
		}
		for _, v := range devList {
			ruleSns = append(ruleSns, v.Sn)
		}
	}
	return ruleSns
}
